package com.ruoyi.project.determination.algorithm;

import com.ruoyi.project.determination.pojo.AssignmentResults;
import org.apache.commons.math3.optim.MaxIter;
import org.apache.commons.math3.optim.PointValuePair;
import org.apache.commons.math3.optim.linear.*;
import org.apache.commons.math3.optim.nonlinear.scalar.GoalType;

import java.util.*;

public class test {

    public AssignmentResults compute(double[][] costMatrix, int[] demandVector, int[][] supplyLimitMatrix, int[] maxDemand, double storageCost, List<String> productEnterprises, String product) {
        int numEnterprises = costMatrix.length;  // 企业数量
        int numMonths = costMatrix[0].length;  // 月份数量

        // 决策变量的系数矩阵
        double[] objectiveCoefficients = new double[numEnterprises * numMonths * 2];  // 包含 Tcon 和 Tadv
        int idx = 0;

        // 构建目标函数
        for (int i = 0; i < numEnterprises; i++) {
            for (int j = 0; j < numMonths; j++) {
                // Q[i,j] * T[i,j]
//                objectiveCoefficients[idx++] = costMatrix[i][j];
//                objectiveCoefficients[idx++] = costMatrix[i][j];  // Tcon 和 Tadv 的系数相同
                objectiveCoefficients[i * numMonths + j] = costMatrix[i][j];
                objectiveCoefficients[numEnterprises * numMonths + i * numMonths + j] = costMatrix[i][j];
            }
        }

        // 构建线性目标函数
        LinearObjectiveFunction objectiveFunction = new LinearObjectiveFunction(objectiveCoefficients, 0);

        // 添加约束条件
        List<LinearConstraint> constraints = new ArrayList<>();

        // 约束 (3.9) 和 (3.10): Tcon[i,j] 和 Tadv[i,j] 是非负整数，且 Tcon[i,j] + Tadv[i,j] <= La[i,j]
        for (int i = 0; i < numEnterprises; i++) {
            for (int j = 0; j < numMonths; j++) {
                double[] sumCoefficients = new double[numEnterprises * numMonths * 2];
                sumCoefficients[i * numMonths + j] = 1.0;  // Tcon[i,j]
                sumCoefficients[numEnterprises * numMonths + i * numMonths + j] = 1.0;  // Tadv[i,j]
                constraints.add(new LinearConstraint(sumCoefficients, Relationship.LEQ, supplyLimitMatrix[i][j]));
            }
        }

        // 约束 (3.11): sum(Tcon[i,j] + Reccon[i,j]) >= L[j]
        for (int j = 0; j < numMonths; j++) {
            double[] sumCoefficients = new double[numEnterprises * numMonths * 2];
            for (int i = 0; i < numEnterprises; i++) {
                sumCoefficients[i * numMonths + j] = 1.0;  // Tcon[i,j]

                // 添加递归消耗 Reccon[i,j] (前一个月的提前分配)
                if (j > 0) {
                    sumCoefficients[numEnterprises * numMonths + i * numMonths + (j - 1)] += 1.0;  // Reccon[i,j] 来自上一个月的 Tadv[i,j-1]
                }
            }
            constraints.add(new LinearConstraint(sumCoefficients, Relationship.GEQ, demandVector[j]));
        }

        // 约束 (3.12): Recsto[j] + sum(T[i,j]) <= U[j]
        for (int j = 0; j < numMonths; j++) {
            double[] sumCoefficients = new double[numEnterprises * numMonths * 2];
            for (int i = 0; i < numEnterprises; i++) {
                sumCoefficients[i * numMonths + j] = 1.0;  // Tcon[i,j]
                sumCoefficients[numEnterprises * numMonths + i * numMonths + j] = 1.0;  // Tadv[i,j]
            }

            // 添加递归存储 Recsto[j]，表示尚未消耗的提前分配
            constraints.add(new LinearConstraint(sumCoefficients, Relationship.LEQ, maxDemand[j]));
        }

        // 求解线性规划问题
        SimplexSolver solver = new SimplexSolver();
        PointValuePair solution = solver.optimize(new MaxIter(1000), objectiveFunction, new LinearConstraintSet(constraints), GoalType.MINIMIZE, new NonNegativeConstraint(true));

        // 解析结果
        double totalCost = solution.getValue();
        double[] solutionVector = solution.getPoint();

        // 构建Tcon和Tadv矩阵
        int[][] Tcon = new int[numEnterprises][numMonths];
        int[][] Tadv = new int[numEnterprises][numMonths];

        for (int i = 0; i < numEnterprises; i++) {
            for (int j = 0; j < numMonths; j++) {
                // 解析 Tcon[i,j] 和 Tadv[i,j]，与构建目标函数时一致的索引规则
                Tcon[i][j] = (int) Math.round(solutionVector[i * numMonths + j]);
                Tadv[i][j] = (int) Math.round(solutionVector[numEnterprises * numMonths + i * numMonths + j]);
            }
        }

        // 构建Reccon和Recsto
        int[][] Reccon = new int[numEnterprises][numMonths];
        double[] Recsto = new double[numMonths];

        for (int j = 0; j < numMonths; j++) {
            double recstoSum = 0.0;
            for (int i = 0; i < numEnterprises; i++) {
                if (j > 0) {
                    Reccon[i][j] = Reccon[i][j - 1] + Tadv[i][j - 1];  // 递归消耗
                } else {
                    Reccon[i][j] = 0;
                }
                recstoSum += Tadv[i][j] - Reccon[i][j];  // 尚未消耗的提前分配
            }
            Recsto[j] = recstoSum * storageCost;  // 存储成本
        }

        // 修正目标函数，将存储成本加到总成本上
        for (int j = 0; j < numMonths; j++) {
            totalCost += Recsto[j];
        }

        // 构建最终的分配矩阵 T[i,j] = Tcon[i,j] + Tadv[i,j]
        int[][] totalAllocationMatrix = new int[numEnterprises][numMonths];
        for (int i = 0; i < numEnterprises; i++) {
            for (int j = 0; j < numMonths; j++) {
                totalAllocationMatrix[i][j] = Tcon[i][j] + Tadv[i][j];  // 计算总分配量
            }
        }

        // 构建 AssignmentResults 对象
        Map<String, Map<String, List<Integer>>> assignmentDetails = new HashMap<>();
        for (int i = 0; i < numEnterprises; i++) {
            String enterprise = productEnterprises.get(i);  // 获取企业名称
            List<Integer> allocations = new ArrayList<>();
            for (int j = 0; j < numMonths; j++) {
                allocations.add(totalAllocationMatrix[i][j]);  // 保存该企业每个月的总分配量
            }
            // 将分配数据放入 assignmentDetails，按产品和企业维度组织
            assignmentDetails.computeIfAbsent(product, k -> new HashMap<>()).put(enterprise, allocations);
        }

        AssignmentResults result = new AssignmentResults();
        result.setScores(totalCost);  // 总成本（包括存储成本）
        result.setAssignmentDetails(assignmentDetails);

        return result;
    }

    // 辅助方法，用于构建约束的系数矩阵
    private double[] buildCoefficients(int numEnterprises, int numMonths, int enterpriseIdx, int monthIdx, double coefficient) {
        double[] coefficients = new double[numEnterprises * numMonths];
        coefficients[enterpriseIdx * numMonths + monthIdx] = coefficient;
        return coefficients;
    }
}
